{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "91713121-11f0-499b-8a19-cfb66a29bda6",
   "metadata": {
    "tags": []
   },
   "source": [
    "# Qwen2模型验证"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "f47847c3-2fff-4cc6-88e9-0bdacfe38b50",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-21T07:23:16.780871Z",
     "iopub.status.busy": "2024-09-21T07:23:16.780701Z",
     "iopub.status.idle": "2024-09-21T07:23:21.682893Z",
     "shell.execute_reply": "2024-09-21T07:23:21.682321Z",
     "shell.execute_reply.started": "2024-09-21T07:23:16.780850Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Looking in indexes: https://mirrors.aliyun.com/pypi/simple\n",
      "Requirement already satisfied: modelscope in /usr/local/lib/python3.10/site-packages (1.18.0)\n",
      "Requirement already satisfied: requests>=2.25 in /usr/local/lib/python3.10/site-packages (from modelscope) (2.32.3)\n",
      "Requirement already satisfied: tqdm>=4.64.0 in /usr/local/lib/python3.10/site-packages (from modelscope) (4.66.4)\n",
      "Requirement already satisfied: urllib3>=1.26 in /usr/local/lib/python3.10/site-packages (from modelscope) (2.2.1)\n",
      "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/site-packages (from requests>=2.25->modelscope) (3.3.2)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/site-packages (from requests>=2.25->modelscope) (2024.2.2)\n",
      "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/site-packages (from requests>=2.25->modelscope) (3.7)\n",
      "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n",
      "\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.0.1\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m24.2\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n"
     ]
    }
   ],
   "source": [
    "!pip install modelscope"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "cb1183c8-29a3-476e-84cd-51b0b1d2e93c",
   "metadata": {
    "ExecutionIndicator": {
     "show": true
    },
    "execution": {
     "iopub.execute_input": "2024-09-21T07:23:21.684828Z",
     "iopub.status.busy": "2024-09-21T07:23:21.684308Z",
     "iopub.status.idle": "2024-09-21T07:23:27.803056Z",
     "shell.execute_reply": "2024-09-21T07:23:27.802461Z",
     "shell.execute_reply.started": "2024-09-21T07:23:21.684806Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "from modelscope import AutoModelForCausalLM,AutoTokenizer\n",
    "import torch\n",
    "\n",
    "device = \"cuda\" # the device to load the model onto\n",
    "\n",
    "model = AutoModelForCausalLM.from_pretrained(\n",
    "    \"qwen/Qwen2-0.5B-Instruct\",\n",
    "    torch_dtype=\"auto\",\n",
    "    device_map=\"auto\"\n",
    ")\n",
    "tokenizer = AutoTokenizer.from_pretrained(\"qwen/Qwen2-0.5B-Instruct\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "1e6d3612-4e69-48c3-b6a7-82f5da95ae4b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-09-21T07:23:27.804133Z",
     "iopub.status.busy": "2024-09-21T07:23:27.803814Z",
     "iopub.status.idle": "2024-09-21T07:23:27.807644Z",
     "shell.execute_reply": "2024-09-21T07:23:27.807072Z",
     "shell.execute_reply.started": "2024-09-21T07:23:27.804109Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Qwen2TokenizerFast(name_or_path='/mnt/workspace/.cache/modelscope/hub/qwen/Qwen2-0___5B-Instruct', vocab_size=151643, model_max_length=32768, is_fast=True, padding_side='right', truncation_side='right', special_tokens={'eos_token': '<|im_end|>', 'pad_token': '<|endoftext|>', 'additional_special_tokens': ['<|im_start|>', '<|im_end|>']}, clean_up_tokenization_spaces=False),  added_tokens_decoder={\n",
      "\t151643: AddedToken(\"<|endoftext|>\", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),\n",
      "\t151644: AddedToken(\"<|im_start|>\", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),\n",
      "\t151645: AddedToken(\"<|im_end|>\", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),\n",
      "}\n"
     ]
    }
   ],
   "source": [
    "print(tokenizer)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "4a92426f-1098-48f2-8c56-d473e5ba5d18",
   "metadata": {
    "ExecutionIndicator": {
     "show": true
    },
    "execution": {
     "iopub.execute_input": "2024-09-21T07:23:27.808639Z",
     "iopub.status.busy": "2024-09-21T07:23:27.808435Z",
     "iopub.status.idle": "2024-09-21T07:23:27.812761Z",
     "shell.execute_reply": "2024-09-21T07:23:27.812282Z",
     "shell.execute_reply.started": "2024-09-21T07:23:27.808620Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "def chat(prompt):\n",
    "    messages = [\n",
    "        {\"role\": \"system\", \"content\": \"You are a helpful assistant.\"},\n",
    "        {\"role\": \"user\", \"content\": prompt},\n",
    "    ]\n",
    "    text = tokenizer.apply_chat_template(\n",
    "        messages,\n",
    "        tokenize=False,\n",
    "        add_generation_prompt=True\n",
    "    )\n",
    "    #print(text)\n",
    "\n",
    "    model_inputs = tokenizer([text], return_tensors=\"pt\").to(device)\n",
    "\n",
    "    generated_ids = model.generate(\n",
    "        model_inputs.input_ids,\n",
    "        max_new_tokens=512\n",
    "    )\n",
    "    generated_ids = [\n",
    "        output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids)\n",
    "    ]\n",
    "\n",
    "    response = tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]\n",
    "    return response"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "a45aafdf-6aed-47f3-84a5-c06ce45aaab4",
   "metadata": {
    "ExecutionIndicator": {
     "show": true
    },
    "execution": {
     "iopub.execute_input": "2024-09-21T07:23:27.813642Z",
     "iopub.status.busy": "2024-09-21T07:23:27.813395Z",
     "iopub.status.idle": "2024-09-21T07:23:29.135149Z",
     "shell.execute_reply": "2024-09-21T07:23:29.134650Z",
     "shell.execute_reply.started": "2024-09-21T07:23:27.813622Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "The attention mask is not set and cannot be inferred from input because pad token is same as eos token. As a consequence, you may observe unexpected behavior. Please pass your input's `attention_mask` to obtain reliable results.\n",
      "Starting from v4.46, the `logits` model output will have the same type as the model (except at train time, where it will always be FP32)\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'我是来自阿里云的大规模语言模型，我叫通义千问。'"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "prompt = \"你是谁？\"\n",
    "chat(prompt)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "6ccd478e-5354-43a9-8d4a-2e4e1a0b46e5",
   "metadata": {
    "ExecutionIndicator": {
     "show": true
    },
    "execution": {
     "iopub.execute_input": "2024-09-21T07:23:29.136185Z",
     "iopub.status.busy": "2024-09-21T07:23:29.135930Z",
     "iopub.status.idle": "2024-09-21T07:23:29.142901Z",
     "shell.execute_reply": "2024-09-21T07:23:29.142420Z",
     "shell.execute_reply.started": "2024-09-21T07:23:29.136164Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "# 训练数据预处理方法\n",
    "def preprocess(tokenizer,batch_messages):\n",
    "    input_list=[]\n",
    "    target_list=[]\n",
    "    \n",
    "    im_start=tokenizer('<|im_start|>').input_ids\n",
    "    im_end=tokenizer('<|im_end|>').input_ids\n",
    "    newline=tokenizer('\\n').input_ids\n",
    "    pad=tokenizer('<|endoftext|>').input_ids\n",
    "    ignore=[-100]\n",
    "    \n",
    "    for group in batch_messages:\n",
    "        input_ids=[]\n",
    "        target_ids=[]\n",
    "        for msg in group:\n",
    "            role=tokenizer(msg['role']).input_ids\n",
    "            content=tokenizer(msg['content']).input_ids\n",
    "            if msg['role'] in ['system','user']:\n",
    "                ignore_parts=role+newline+content\n",
    "                input_ids+=im_start+ignore_parts+im_end+newline\n",
    "                target_ids+=im_start+ignore*len(ignore_parts)+im_end+newline\n",
    "            else:\n",
    "                ignore_parts=role+newline\n",
    "                input_ids+=im_start+ignore_parts+content+im_end+newline\n",
    "                target_ids+=im_start+ignore*len(ignore_parts)+content+im_end+newline\n",
    "        input_list.append(input_ids)\n",
    "        target_list.append(target_ids)\n",
    "    \n",
    "    # padding\n",
    "    max_len=max([len(ids) for ids in input_list])\n",
    "    for input_ids,target_ids in zip(input_list,target_list):\n",
    "        input_ids+=pad*(max_len-len(input_ids))\n",
    "        target_ids+=ignore*(max_len-len(target_ids))\n",
    "    batch_input_ids=torch.tensor(input_list,dtype=torch.long)\n",
    "    batch_target_ids=torch.tensor(target_list,dtype=torch.long)\n",
    "    batch_mask=batch_input_ids.ne(pad[0]).type(torch.long)\n",
    "    return batch_input_ids,batch_target_ids,batch_mask"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "221b021f-eccd-40d9-bf4e-d3b39b5bfd1d",
   "metadata": {},
   "source": [
    "# 训练数据测试"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "5433da08-9def-4c3b-982f-d49e22161e96",
   "metadata": {
    "ExecutionIndicator": {
     "show": true
    },
    "execution": {
     "iopub.execute_input": "2024-09-21T07:23:39.399356Z",
     "iopub.status.busy": "2024-09-21T07:23:39.399015Z",
     "iopub.status.idle": "2024-09-21T07:23:39.470823Z",
     "shell.execute_reply": "2024-09-21T07:23:39.470296Z",
     "shell.execute_reply.started": "2024-09-21T07:23:39.399333Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "logits: torch.Size([2, 31, 151936])\n",
      "targets: torch.Size([2, 31])\n",
      "loss: tensor(0.0090, device='cuda:0', grad_fn=<NllLossBackward0>)\n"
     ]
    }
   ],
   "source": [
    "prompt = \"2+2等于几\"\n",
    "messages = [\n",
    "    [\n",
    "        {\"role\": \"system\", \"content\": \"You are a helpful assistant.\"},\n",
    "        {\"role\": \"user\", \"content\": prompt},\n",
    "        {\"role\": \"assistant\", \"content\": '2+2等于5。'},\n",
    "    ],\n",
    "    [\n",
    "        {\"role\": \"system\", \"content\": \"You are a helpful assistant.\"},\n",
    "        {\"role\": \"user\", \"content\": prompt},\n",
    "        {\"role\": \"assistant\", \"content\": '2+2等于5。'},\n",
    "    ]\n",
    "]\n",
    "\n",
    "model.eval()\n",
    "\n",
    "batch_input_ids,batch_target_ids,batch_mask=preprocess(tokenizer,messages)\n",
    "model_outputs=model(batch_input_ids.to(device))\n",
    "\n",
    "output_tokens=model_outputs.logits.argmax(dim=-1)\n",
    "\n",
    "logits=model_outputs.logits[:,:-1,:]\n",
    "targets=batch_target_ids[:,1:].to(device)\n",
    "print('logits:',logits.shape) # 模型输出\n",
    "print('targets:',targets.shape) # 拟合目标\n",
    "\n",
    "from torch.nn import CrossEntropyLoss\n",
    "\n",
    "# 损失\n",
    "loss_fn=CrossEntropyLoss()\n",
    "loss=loss_fn(logits.reshape(-1,logits.size(2)),targets.reshape(-1))\n",
    "print('loss:',loss)\n",
    "\n",
    "# 优化器\n",
    "optimizer=torch.optim.SGD(model.parameters())\n",
    "optimizer.zero_grad()\n",
    "\n",
    "# 求梯度\n",
    "loss.backward()\n",
    "\n",
    "# 梯度下降\n",
    "optimizer.step()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "3f72c302-f842-48f5-95c1-89d1101a2737",
   "metadata": {
    "ExecutionIndicator": {
     "show": true
    },
    "execution": {
     "iopub.execute_input": "2024-09-21T07:23:45.741993Z",
     "iopub.status.busy": "2024-09-21T07:23:45.741624Z",
     "iopub.status.idle": "2024-09-21T07:23:45.885587Z",
     "shell.execute_reply": "2024-09-21T07:23:45.885085Z",
     "shell.execute_reply.started": "2024-09-21T07:23:45.741969Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'2+2等于5。'"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chat('2+2等于4么')"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.14"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
